/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.gwtgui.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;

import com.google.gson.Gson;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.EvidenceInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.LWPException;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.ModelInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.QueryInfo;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.QueryOptionsGWT;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.TreeNode;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.TreeNode.TreeType;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.UserInfo;
import com.sri.ai.lpitools.cobra.interfaces.api.COBRAInterface;
import com.sri.ai.lpitools.executionengine.interfaces.api.ExecutionEngineInterface;
import com.sri.ai.lpitools.gwtgui.callback.RPCMultiCallBackServerImpl;
import com.sri.ai.lpitools.gwtgui.client.RPCService;
import com.sri.ai.lpitools.gwtgui.client.components.dialogs.MessageDialog;
import com.sri.ai.lpitools.gwtgui.server.util.TreeNodeCollection;
import com.sri.ai.lpitools.latex.interfaces.api.LatexInterface;

@SuppressWarnings("serial")
public class RPCServiceImpl extends RemoteServiceServlet implements RPCService {

	private static Logger logger = Logger.getLogger(RPCServiceImpl.class.getName());
	private static final String configFile = "ServerSettings.config";
	
	//container unique name to use as a key to retrieve session variables
	private static String treeNodesKey = RPCServiceImpl.class.getName() + ".nodes";
	
	/**
	 * The TreeNodeCollection is unique per http session, so we need to store it in the httpSession
	 * which is maintained by the web container.  This protects the Nodes and ensures that each
	 * http session has it's own view of the tree nodes.  This also pushes management of the nodes
	 * into the web container.  When the session is closed, the memory will be reclaimed.
	 * @return
	 */
	private TreeNodeCollection getTreeNodeCollection() {
		
		HttpSession httpSession = this.getThreadLocalRequest().getSession();
		synchronized (httpSession) {
			TreeNodeCollection treeNodes = (TreeNodeCollection)httpSession.getAttribute(treeNodesKey);
			if (treeNodes == null) {
				treeNodes = new TreeNodeCollection();
				httpSession.setAttribute(treeNodesKey, treeNodes);
			}
			return treeNodes;
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getModelJSON(java.lang.String)
	 */
	@Override
	public String getModel(String user, String title) throws LWPException {
		
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		if(cInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation." );
		} else{ 
			cInterface.setUp(url);
		}

		return cInterface.getModelByName(user, title);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getModelList()
	 */
	@Override
	public String getModelList(String user) throws LWPException {

		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}

		return cInterface.listModels(user);
	}
	
	@Override
	public boolean saveModel(String user, String title, ModelInfo model) throws LWPException {
		
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
		
		String modelString = new Gson().toJson(model);
		if(cInterface==null) {
			throw new LWPException ( "Unable to instantiate specified COBRA implementation." );
		} else {
			cInterface.setUp(url);
		}

		return cInterface.saveModel(user, title, modelString);
	}

	@Override
	public boolean saveModelInfo(String user, String title, ModelInfo model) throws LWPException {
		
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		String modelString = new Gson().toJson(model);
		if(cInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation." );
		}
		else{
			cInterface.setUp(url);
		}

		return cInterface.saveModelInfo(user, title, modelString);
	}	
	
	@Override
	public boolean saveModelBody(String user, String title, ModelInfo model) throws LWPException {
		
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		String modelString = new Gson().toJson(model);
		if(cInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation." );
		} else {
			cInterface.setUp(url);
		}

		return cInterface.saveModelBody(user, title, modelString);
	}	
		
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#checkModel(java.lang.String)
	 */
	@Override
	public boolean checkModel(String model) throws LWPException {
		
		String url = getURLExecutionEngine();
		ExecutionEngineInterface eeInterface = instantiateExecutionEngine();

		if(eeInterface==null) {
			throw new LWPException( "Unable to instantiate specified Execution Engine implementation." );
		} else {
			eeInterface.setUp(url);
		}
		return eeInterface.checkModelByModel(model);
	}

	@Override
	public String runQuery(String user, String model, String evidenceTitle, String query, QueryOptionsGWT queryOptions) throws LWPException {
		
		String clientURL = getURLExecutionEngine();
		ExecutionEngineInterface eeInterface = instantiateExecutionEngine();

		if(eeInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation." );
		} else {
			eeInterface.setUp(clientURL);
		}
	  
		String clientID = eeInterface.getID();
		sendClientIDToClient(clientID);
		RPCMultiCallBackServerImpl server = new RPCMultiCallBackServerImpl();
		String url = "";
		try {
			url = server.startServer();
		} catch (XmlRpcException e) {
			logger.info(e.toString());
		} catch (IOException e) {
			logger.info(e.toString());
		}
		HttpSession httpSession = this.getThreadLocalRequest().getSession();
		CallBackListenerInterface listener = new CallBackListener(httpSession, treeNodesKey);
		
		server.addListener(clientID, listener);

		Gson gson = new Gson();
		String queryOptionsJSON = gson.toJson(queryOptions);
		
		String result = eeInterface.runQuery(user, model, evidenceTitle, query, clientID, queryOptionsJSON, url);
				
		return result;
	}


	/**
	 * This funvtion send the id to the client
	 * @param clientID
	 */
	private void sendClientIDToClient(String clientID) {
		ServerMessageGeneratorServiceImpl x = new ServerMessageGeneratorServiceImpl();
		x.sendClientID(clientID);
	}

	@Override
	public boolean saveQuery(String user, QueryInfo query) throws LWPException {
		
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		String queryString = new Gson().toJson(query);
		if(cInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}

		return cInterface.saveQuery(user, query.getQueryTitle(), queryString);
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getEvedenceList(java.lang.String)
	 */
	@Override
	public String getEvidenceList(String user) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}

		return cInterface.listEvidences(user);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getQueryList(java.lang.String)
	 */
	@Override
	public String getQueryList(String user) throws LWPException {
		
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
		
		if(cInterface==null) {
			throw new LWPException("ERROR. \n Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}

		return cInterface.listQueries(user);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#deletModelByKey(java.lang.String)
	 */
	@Override
	public boolean deleteModelByKey(String user, String modelName) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
		
		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}
 
		return cInterface.deleteModel(user, modelName);
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#deleteQuery(java.lang.String, java.lang.String)
	 */
	@Override
	public boolean deleteQuery(String user, String query) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}

		return cInterface.deleteQuery(user, query);
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#checkUser(java.lang.String)
	 */
	@Override
	public String checkUser(String user) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
		
		if(cInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation." );
		} else {
			cInterface.setUp(url);
		}

		String userInfo = cInterface.authenticateUser(user);
		if(userInfo != null) {;
			return userInfo;
		} else {
			throw new LWPException("Requested User not valid");
		}
	}
		
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getID()
	 */
	@Override
	public String getID() throws LWPException {
		String url = getURLExecutionEngine();
		ExecutionEngineInterface eeInterface = instantiateExecutionEngine();

		if(eeInterface==null) {
			throw new LWPException( "Unable to instantiate specified Execution Engine implementation." );
		} else {
			eeInterface.setUp(url);
		}
		
		String id = eeInterface.getID();
		return id;
	}
	/**
	 * Instantiates a COBRA Implementation.
	 * Gets which to instantiate from config file.
	 * @return True if able to instantiate, false if unable.
	 */
	private COBRAInterface instantiateCOBRA() {
		String className = null;
		
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(configFile);
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String strLine = null;
		boolean found = false;
		
		try {
			while (!found && (strLine = reader.readLine()) != null)   {
				if(strLine.contains("COBRAImplementation")){
					found = true;
					reader.close();
				}
			}
		} catch (IOException e1) {
			logger.error("Unable to read config file " + configFile, e1);
			return null;
		}
		if(found) {
			String[] split = strLine.split("=");
			if(split.length != 2) {
				logger.error("Bad config file data " + strLine);
				return null;
			}
			className = split[1];
		} else {
			logger.error("Unable to find COBRAImplementation line in config file.");
			return null;
		}
		
		Class<?> toMake = null;
		try {
			toMake = Class.forName(className);
		} catch (ClassNotFoundException e) {
			logger.error("Unable to find class: " + className, e);
			return null;
		}
		boolean isCOBRA = false;
		for(Class<?> i: toMake.getInterfaces()) {
			if(i.getName().equals(COBRAInterface.class.getName())) {
				isCOBRA = true;
			}
		}
		if(!isCOBRA) return null; //Not a COBRA Implementation.
		Constructor<?> constructor = null;
		try {
			constructor = toMake.getConstructor();
		} catch (SecurityException e) {
			logger.error("Security Violation", e);
			return null;
		} catch (NoSuchMethodException e) {
			logger.error("Unable to find constructor for class: " + className, e);
			return null;
		}
		try {
			COBRAInterface cInterface = (COBRAInterface) constructor.newInstance();
			return cInterface;
		} catch (Exception e) {
			logger.error("Unable to instantiate class", e);
			return null;
		}
	}
	
	/**
	 * Instantiates an Execution EngineImplementation.
	 * Gets which to instantiate from config file.
	 * @return True if able to instantiate, false if unable.
	 */
	private ExecutionEngineInterface instantiateExecutionEngine() {
		String className = null;
		
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(configFile);
		if (in == null) {
			logger.info("Unable to open resource " + configFile);
			return null;
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String strLine = null;
		boolean found = false;
		
		try {
			while (!found && (strLine = reader.readLine()) != null)   {
				if(strLine.contains("ExecutionEngineImplementation")){
					found = true;
					reader.close();
				}
			}
		} catch (IOException e1) {
			logger.info("Unable to read config file "+ e1.toString());
			return null;
		}
		if(found)
		{
			String[] split = strLine.split("=");
			if(split.length != 2)
			{
				logger.info("Bad config file data");
				return null;
			}
			className = split[1];
		}
		else
		{
			logger.info("Unable to find ExecutionEngineImplementation line in config file.");
			return null;
		}
		
		Class<?> toMake = null;
		try {
			toMake = Class.forName(className);
		} catch (ClassNotFoundException e) {
			logger.info("Unable to find class: " + className +  e.toString());
			return null;
		}
		boolean isEE = false;
		for(Class<?> i: toMake.getInterfaces())
		{
			if(i.getName().equals(ExecutionEngineInterface.class.getName()))
			{
				isEE = true;
			}
		}
		if(!isEE){
			return null; //Not a COBRA Implementation.
		}
		Constructor<?> constructor = null;
		try {
			constructor = toMake.getConstructor();
		} catch (SecurityException e) {
			logger.info("Security Violation " + e.toString());
			return null;
		} catch (NoSuchMethodException e) {
			logger.info("Unable to find constructor for class: " + className + e.toString());
			return null;
		}
		try {
			ExecutionEngineInterface eeInterface = (ExecutionEngineInterface) constructor.newInstance();
			return eeInterface;
		} catch (Exception e) {
			logger.info("Unable to instantiate class " + e.toString());
			return null;
		}
	}

	@Override
	public boolean deleteEvidence(String user, String evidenceName) throws LWPException {
		// TODO ask COBRA to delete the evidence
		return false;
	}

	@Override
	public String listUsers() throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		if(cInterface==null) {
			throw new LWPException( "Unable to instantiate specified COBRA implementation." );
		} else {
			cInterface.setUp(url);
		}
		
		return cInterface.getUsers();
	}

	private String getURLCOBRA() {
		String url = null;
		
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(configFile);
		if (in == null) {
			logger.info("Unable to open resource " + configFile);
			return "127.0.0.1:8095";
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String strLine = null;
		boolean found = false;
		
		try {
			while (!found && (strLine = reader.readLine()) != null)   {
				if(strLine.contains("COBRALocation")){
					found = true;
					reader.close();
				}
			}
		} catch (IOException e1) {
			logger.info("Unable to read config file " + e1.toString());
			return "127.0.0.1:8095";
		}
		if(found)
		{
			String[] split = strLine.split("=");
			if(split.length != 2)
			{
				logger.info("Bad config file data");
				return "127.0.0.1:8095";
			}
			url = split[1];
			if(url.contains("local")){
				String localHostIP = getHostIP();
				if(!localHostIP.equalsIgnoreCase("")){
					url = url.replaceAll("local", localHostIP);
				}
				else{
					url = url.replaceAll("local", "127.0.0.1");
				}
			}
			return url;
		}
		else{
			return "127.0.0.1:8095";
		}
	}
	
	
	private String getURLExecutionEngine() {
		String url = null;
		
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(configFile);
		if (in == null) {
			logger.info("Unable to open resource " + configFile);
			return "127.0.0.1:8099";
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String strLine = null;
		boolean found = false;
		
		try {
			while (!found && (strLine = reader.readLine()) != null)   {
				if(strLine.contains("ExecutionEngineLocation")){
					found = true;
					reader.close();
				}
			}
		} catch (IOException e1) {
			logger.info("Unable to read config file " + e1.toString());
			return "127.0.0.1:8099";
		}
		if(found)
		{
			String[] split = strLine.split("=");
			if(split.length != 2)
			{
				logger.info("Bad config file data");
				return "127.0.0.1:8099";
			}
			url = split[1];
			if(url.contains("local")){
				String localHostIP = getHostIP();
				if(!localHostIP.equalsIgnoreCase("")){
					url = url.replaceAll("local", localHostIP);
				}
				else{
					url = url.replaceAll("local", "127.0.0.1");
				}
			}
			return url;
		}
		else{
			return "127.0.0.1:8099";
		}
	}
	
	private String getHostIP() {
		try {
			return java.net.InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e) {
			logger.error("Unable to get host address", e);
		}
		return "";
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getNodeChildren(java.lang.String, java.lang.String, com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.TreeNode.TreeType)
	 */
	@Override
	public ArrayList<TreeNode> getNodeChildren(String nodeID, String clientID, TreeType nodeType) throws LWPException {
		return getTreeNodeCollection().getNodesForParent(clientID, nodeID, nodeType);
	}

	/* 
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getQuery(java.lang.String, java.lang.String)
	 */
	@Override
	public QueryInfo getQuery(String user, String queryTitle) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		
		if(cInterface==null)
		{
			MessageDialog.showMessageDialog("ERROR. \n Unable to instantiate specified COBRA implementation.");
			return null;
		}
		else{
			cInterface.setUp(url);
		}
		
		
		String resultQuery = cInterface.getQuery(user, queryTitle);
		Gson gson = new Gson();
		QueryInfo query = gson.fromJson(resultQuery, QueryInfo.class);
		return query;
	}

	/* 
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getEvidence(java.lang.String, java.lang.String)
	 */
	@Override
	public EvidenceInfo getEvidence(String user, String evidenceTitle) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
		
		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}
		
		String resultEvidence = cInterface.getEvidence(user, evidenceTitle);
		Gson gson = new Gson();
		EvidenceInfo evidence = gson.fromJson(resultEvidence, EvidenceInfo.class);
		return evidence;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#deleteUser(java.lang.String)
	 */
	@Override
	public boolean deleteUser(String userName) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();

		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}
		
		return cInterface.deleteUser(userName);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#saveUser(com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.UserInfo)
	 */
	@Override
	public boolean saveUser(UserInfo user) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
	
		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}
		
		Gson gson = new Gson();
		String userInfo = gson.toJson(user);
		return cInterface.saveUser(userInfo);
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#saveEvidence(java.lang.String, com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.EvidenceInfo)
	 */
	@Override
	public boolean saveEvidence(String user, EvidenceInfo evidence) throws LWPException {
		String url = getURLCOBRA();
		COBRAInterface cInterface= instantiateCOBRA();
		
		if(cInterface==null) {
			throw new LWPException("Unable to instantiate specified COBRA implementation.");
		} else {
			cInterface.setUp(url);
		}
		
		String evidenceString = new Gson().toJson(evidence);
		return cInterface.saveEvidences(user, evidence.getEvidenceTitle(), evidenceString);
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getLatexImage(java.lang.String)
	 */
	@Override
	public String getLatexImage(String queryResult) throws LWPException {
		String url = getURLLatex();
		LatexInterface lInterface= instantiateLatex();

		if(lInterface==null) {
			throw new LWPException("Unable to connect to LatexInterface");
		}
		else{
			lInterface.setUp(url);
		}
		String result = lInterface.getTexLiveImage(queryResult);
		if(result != null){
				return result;
		} else {
			throw new LWPException("Error with TEXLive image creating");
		}
	}
	
	/**
	 * Function to get the latex interface object from
	 * @return
	 */
	private LatexInterface instantiateLatex() {
		String className = null;
		
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(configFile);
		if (in == null) {
			logger.info("Unable to open resource " + configFile);
			return null;
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String strLine = null;
		boolean found = false;
		
		try {
			while (!found && (strLine = reader.readLine()) != null)   {
				if(strLine.contains("LatexImplementation")){
					found = true;
					reader.close();
				}
			}
		} catch (IOException e1) {
			logger.info("Unable to read config file "+ e1.toString());
			return null;
		}
		if(found)
		{
			String[] split = strLine.split("=");
			if(split.length != 2)
			{
				logger.info("Bad config file data");
				return null;
			}
			className = split[1];
		}
		else
		{
			logger.info("Unable to find ExecutionEngineImplementation line in config file.");
			return null;
		}
		
		Class<?> toMake = null;
		try {
			toMake = Class.forName(className);
		} catch (ClassNotFoundException e) {
			logger.info("Unable to find class: " + className +  e.toString());
			return null;
		}
		boolean isLI = false;
		for(Class<?> i: toMake.getInterfaces())
		{
			if(i.getName().equals(LatexInterface.class.getName()))
			{
				isLI = true;
			}
		}
		if(!isLI){
			return null; //Not a COBRA Implementation.
		}
		Constructor<?> constructor = null;
		try {
			constructor = toMake.getConstructor();
		} catch (SecurityException e) {
			logger.info("Security Violation " + e.toString());
			return null;
		} catch (NoSuchMethodException e) {
			logger.info("Unable to find constructor for class: " + className + e.toString());
			return null;
		}
		try {
			LatexInterface lInterface = (LatexInterface) constructor.newInstance();
			return lInterface;
		} catch (Exception e) {
			logger.info("Unable to instantiate class " + e.toString());
			return null;
		}
	}

	/**
	 * Funtion to get the url of the latex object from
	 * @return
	 */
	private String getURLLatex() {
		String url = null;
		
		InputStream in = this.getClass().getClassLoader().getResourceAsStream(configFile);
		if (in == null) {
			logger.info("Unable to open resource " + configFile);
			return "127.0.0.1:8102";
		}
		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
		String strLine = null;
		boolean found = false;
		
		try {
			while (!found && (strLine = reader.readLine()) != null)   {
				if(strLine.contains("LatexLocation")){
					found = true;
					reader.close();
				}
			}
		} catch (IOException e1) {
			logger.info("Unable to read config file " + e1.toString());
			return "127.0.0.1:8102";
		}
		if(found)
		{
			String[] split = strLine.split("=");
			if(split.length != 2)
			{
				logger.info("Bad config file data");
				return "127.0.0.1:8102";
			}
			url = split[1];
			if(url.contains("local")){
				String localHostIP = getHostIP();
				if(!localHostIP.equalsIgnoreCase("")){
					url = url.replaceAll("local", localHostIP);
				}
				else{
					url = url.replaceAll("local", "127.0.0.1");
				}
			}
			return url;
		}
		else{
			return "127.0.0.1:8102";
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getHttpSession()
	 */
	@Override
	public String getHttpSession() {
		return this.getThreadLocalRequest().getSession().toString();
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#setUserData(java.lang.String)
	 */
	@Override
	public boolean setUserData(String userInfo) {
		HttpSession currentSession = this.getThreadLocalRequest().getSession();
		currentSession.setAttribute("User", userInfo);
		
		String test = (String) currentSession.getAttribute("User");
		if(test.equalsIgnoreCase(userInfo)){
			return true;
		}
		return false;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#getUserData()
	 */
	@Override
	public String getUserData() {
		HttpSession currentSession = this.getThreadLocalRequest().getSession();
		
		String userInfo = (String) currentSession.getAttribute("User");
		if(userInfo == null){
			return RPCService.invalidReturnString;
		}
		return userInfo;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#checkHttpSession(java.lang.String)
	 */
	@Override
	public boolean checkHttpSession(String sessionID) {
		String currentSessionId = this.getThreadLocalRequest().getSession().toString();
		
		if(currentSessionId.equalsIgnoreCase(sessionID)){
			return true;
		}
		return false;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.sri.ai.lpitools.gwtgui.client.RPCService#resetSession()
	 */
	@Override
	public boolean resetSession() {
		HttpSession currentSession = this.getThreadLocalRequest().getSession();
		currentSession.invalidate();
		return true;
	}
}
